#!/bin/bash
###############################################################################
# 测试脚本 - 自动化测试完整 ETL 数据流
# 
# 功能：
#   1. 扫描 mock-data/test-cases/ 目录中的所有报文
#   2. 逐个发送到 API Gateway
#   3. 等待 Event Processor 处理完成
#   4. 验证数据是否写入 PostgreSQL
#   5. 生成测试报告
#
# 使用：./scripts/test-pipeline.sh
###############################################################################

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# 配置
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
TEST_CASES_DIR="$PROJECT_ROOT/mock-data/test-cases"
TEST_RESULTS_DIR="$PROJECT_ROOT/mock-data/test-results"

# 从部署脚本保存的文件中读取 API endpoint
if [ -f "/tmp/browse-etl-api-endpoint.txt" ]; then
    API_GATEWAY_URL=$(cat /tmp/browse-etl-api-endpoint.txt)
else
    echo "❌ API endpoint 未找到，请先运行: make deploy"
    exit 1
fi

WAIT_TIMEOUT=180  # 超时时间（秒）- 批量处理需要更长时间
POLL_INTERVAL=1   # 轮询间隔（秒）
GRACE_PERIOD=60   # 宽限期（秒）- 等待最后一批处理完成

# 统计变量
TOTAL_TESTS=0        # 测试文件数
TOTAL_EVENTS=0       # 总事件数
PASSED_TESTS=0       # 成功处理的事件数
FAILED_TESTS=0       # 失败的事件数
START_TIME=$(date +%s)
TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
REPORT_FILE="$TEST_RESULTS_DIR/run_${TIMESTAMP}.log"

# 创建测试结果目录
mkdir -p "$TEST_RESULTS_DIR"

###############################################################################
# 辅助函数
###############################################################################

log_info() {
    echo -e "${CYAN}ℹ️  $1${NC}"
}

log_success() {
    echo -e "${GREEN}✅ $1${NC}"
}

log_warning() {
    echo -e "${YELLOW}⚠️  $1${NC}"
}

log_error() {
    echo -e "${RED}❌ $1${NC}"
}

log_section() {
    echo ""
    echo -e "${BLUE}$1${NC}"
    echo "=================================================="
}

# 获取 PostgreSQL 中的记录数
get_db_count() {
    docker exec browse-etl-postgres psql -U postgres -d behavior_analysis -t -c \
        "SELECT COUNT(*) FROM user_behaviors;" 2>/dev/null | xargs || echo "0"
}

# 提取JSON内容（智能处理）
extract_json() {
    local file=$1
    local content=$(cat "$file")
    
    # 1. 如果整个文件是合法JSON，直接返回
    if echo "$content" | python3 -m json.tool > /dev/null 2>&1; then
        echo "$content"
        return 0
    fi
    
    # 2. 尝试提取嵌入的JSON（查找 { ... } 结构）
    local extracted=$(echo "$content" | grep -o '{.*}' | head -1)
    if [ -n "$extracted" ] && echo "$extracted" | python3 -m json.tool > /dev/null 2>&1; then
        echo "$extracted"
        return 0
    fi
    
    # 3. 无法提取JSON，返回原始内容（交给LLM处理）
    echo "$content"
    return 0
}

# 发送事件到 API Gateway
send_event() {
    local file=$1

    # 提取/处理文件内容到临时文件
    local tmp_file="/tmp/event_payload_$$.json"
    extract_json "$file" > "$tmp_file"

    # 统一通过 API Gateway（所有模式），从文件读取以支持大payload
    local response=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X POST "$API_GATEWAY_URL" \
        -H 'Content-Type: application/json' \
        -d @"$tmp_file" 2>&1)

    # 清理临时文件
    rm -f "$tmp_file"

    # 提取HTTP状态码
    local http_code=$(echo "$response" | grep "HTTP_CODE:" | cut -d: -f2)
    local body=$(echo "$response" | grep -v "HTTP_CODE:")

    # 检查响应（200/201 都算成功）
    if [[ "$http_code" == "200" ]] || [[ "$http_code" == "201" ]] || echo "$body" | grep -q '"success".*true'; then
        echo "success"
    else
        echo "failed: HTTP $http_code - $body"
    fi
}

# 等待新记录出现在数据库中
wait_for_db_record() {
    local initial_count=$1
    local timeout=$2
    local elapsed=0
    
    while [ $elapsed -lt $timeout ]; do
        current_count=$(get_db_count)
        if [ "$current_count" -gt "$initial_count" ]; then
            return 0
        fi
        sleep $POLL_INTERVAL
        elapsed=$((elapsed + POLL_INTERVAL))
    done
    
    return 1
}

# 获取最新记录的详细信息（转义特殊字符）
get_latest_record() {
    docker exec browse-etl-postgres psql -U postgres -d behavior_analysis -t -A -F'|' -c \
        "SELECT behavior_type, analysis_method, LEFT(REPLACE(REPLACE(behavior_description, E'\\n', ' '), '''', ''), 50) 
         FROM user_behaviors 
         ORDER BY created_at DESC 
         LIMIT 1;" 2>/dev/null | tr -d '\n' | tr -d '\r'
}

###############################################################################
# 主测试流程
###############################################################################

main() {
    log_section "🧪 ETL Pipeline 自动化测试"
    
    # 检查服务状态
    log_info "检查服务状态..."
    if ! docker ps | grep -q "browse-etl-localstack"; then
        log_error "LocalStack 未运行，请先执行: make start"
        exit 1
    fi
    
    # 检查是否有处理器在运行（Event Processor 或 Flink Agents 或 Lambda）
    if docker ps | grep -q "browse-etl-event-processor"; then
        PROCESSOR_MODE="consumer.py"
    elif docker ps | grep -q "browse-etl-flink-agents-processor"; then
        PROCESSOR_MODE="Flink Agents (本地模式)"
    elif docker ps | grep -q "browse-etl-flink-cluster-processor"; then
        PROCESSOR_MODE="Flink Agents (集群模式)"
    elif docker ps | grep -q "browse-etl-flink-java-jobmanager"; then
        PROCESSOR_MODE="Flink LLM Java (集群模式)"
        log_info "检测到 Java Flink LLM 集群运行中"
    elif docker ps | grep -q "browse-etl-flink-jobmanager"; then
        PROCESSOR_MODE="Flink Agents (集群模式 - 待处理)"
        log_info "Flink 集群已就绪，测试数据将发送到 Kinesis，稍后需手动触发处理"
    else
        # 检查是否是 Lambda 模式（通过检查 Lambda 函数是否存在）
        LAMBDA_EXISTS=$(docker exec browse-etl-localstack awslocal lambda get-function \
            --function-name behavior-processor --region us-east-1 2>/dev/null | grep -c "behavior-processor" || echo "0")

        if [ "$LAMBDA_EXISTS" -gt 0 ]; then
            PROCESSOR_MODE="Lambda (behavior-processor)"
            log_info "检测到 Lambda 模式，事件将由 LocalStack Lambda 处理"
        else
            log_error "没有处理器在运行，请先执行: make start / make start-lambda / make start-flink-local"
            exit 1
        fi
    fi
    
    log_success "所有服务运行正常（处理器: $PROCESSOR_MODE）"
    
    # 扫描测试用例
    log_section "📂 扫描测试用例"
    if [ ! -d "$TEST_CASES_DIR" ]; then
        log_error "测试用例目录不存在: $TEST_CASES_DIR"
        exit 1
    fi
    
    # 扫描所有文件（排除README等文档）
    test_files=($(find "$TEST_CASES_DIR" -type f ! -name "README*" ! -name "*.md" ! -name ".*" | sort))
    TOTAL_TESTS=${#test_files[@]}
    
    if [ $TOTAL_TESTS -eq 0 ]; then
        log_warning "未找到测试用例，请在 $TEST_CASES_DIR 中添加报文文件"
        exit 0
    fi
    
    log_info "找到 $TOTAL_TESTS 个测试用例"
    
    # 记录初始数据库状态
    initial_db_count=$(get_db_count)
    log_info "当前数据库记录数: $initial_db_count"
    
    # 开始测试
    log_section "🚀 开始测试"
    echo ""
    
    # 记录到文件
    {
        echo "================================================================================"
        echo "测试运行报告"
        echo "================================================================================"
        echo "开始时间: $(date)"
        echo "测试用例数: $TOTAL_TESTS"
        echo "初始记录数: $initial_db_count"
        echo ""
    } > "$REPORT_FILE"
    
    # 逐个执行测试
    test_num=0
    for test_file in "${test_files[@]}"; do
        test_num=$((test_num + 1))
        test_name=$(basename "$test_file")
        
        echo -e "${BLUE}[$test_num/$TOTAL_TESTS]${NC} 测试文件: ${CYAN}$test_name${NC}"
        
        # 检查是否是 JSON 数组
        file_content=$(cat "$test_file")
        is_array=$(echo "$file_content" | python3 -c "import sys, json; data=json.load(sys.stdin); print('yes' if isinstance(data, list) else 'no')" 2>/dev/null || echo "no")
        
        if [[ "$is_array" == "yes" ]]; then
            # JSON 数组：批量发送模式
            array_length=$(echo "$file_content" | python3 -c "import sys, json; print(len(json.load(sys.stdin)))" 2>/dev/null || echo "0")
            log_info "检测到 JSON 数组，包含 $array_length 个事件"
            
            # 统计总事件数
            TOTAL_EVENTS=$((TOTAL_EVENTS + array_length))
            
            # 记录测试前的数据库记录数
            before_count=$(get_db_count)
            expected_count=$((before_count + array_length))
            
            # ====== 阶段 1：批量发送（不等待） ======
            echo ""
            log_info "阶段 1/3：批量发送事件..."
            send_success=0
            send_failed=0
            
            for ((i=0; i<array_length; i++)); do
                # 提取单个元素
                tmp_event_file="/tmp/event_${i}_$$.json"
                echo "$file_content" | python3 -c "import sys, json; print(json.dumps(json.load(sys.stdin)[$i]))" > "$tmp_event_file" 2>/dev/null

                # 发送事件（使用 send_event 函数，自动处理 Lambda 模式）
                send_result=$(send_event "$tmp_event_file")

                rm -f "$tmp_event_file"

                if [[ "$send_result" == "success" ]]; then
                    send_success=$((send_success + 1))
                    echo -ne "\r  进度: ${send_success}/${array_length} 已发送"
                else
                    send_failed=$((send_failed + 1))
                fi
            done
            echo ""
            
            if [ $send_failed -gt 0 ]; then
                log_error "发送失败: $send_failed 个事件"
                FAILED_TESTS=$((FAILED_TESTS + send_failed))
            fi
            log_success "发送完成: $send_success/$array_length"
            
            # ====== 阶段 2：等待处理完成 ======
            echo ""
            
            # 集群模式特殊处理：提示用户手动启动处理
            if [[ "$PROCESSOR_MODE" == *"待处理"* ]]; then
                log_info "阶段 2/3：数据已发送到 Kinesis，现在需要启动处理..."
                echo ""
                echo "  请在另一个终端执行以下命令启动处理："
                echo "  ${YELLOW}make start-flink-cluster${NC}"
                echo ""
                echo "  提示：集群模式会处理 Kinesis 中的所有历史数据（包括刚才发送的）"
                echo ""
                read -p "  按 Enter 继续等待处理完成..." -r
                echo ""
            fi
            
            log_info "阶段 2/3：等待处理器处理（最多 ${WAIT_TIMEOUT}s）..."
            echo "  本批次目标: $array_length 个事件"
            
            elapsed=0
            last_count=$before_count
            while [ $elapsed -lt $WAIT_TIMEOUT ]; do
                current_count=$(get_db_count)
                processed=$((current_count - before_count))
                
                # 防止负数（数据库可能被清空）
                if [ $processed -lt 0 ]; then
                    processed=0
                    before_count=$current_count
                fi
                
                if [ "$current_count" -ge "$expected_count" ]; then
                    echo -ne "\r  进度: ${processed}/${array_length} 已处理 ✓          \n"
                    break
                fi
                
                # 显示进度（每秒更新）
                if [ "$current_count" -ne "$last_count" ]; then
                    echo -ne "\r  进度: ${processed}/${array_length} 已处理..."
                    last_count=$current_count
                fi
                
                sleep 1
                elapsed=$((elapsed + 1))
            done

            # 宽限期：如果超时但未完成，等待最后一批处理完成
            if [ $elapsed -ge $WAIT_TIMEOUT ]; then
                current_count=$(get_db_count)
                if [ "$current_count" -lt "$expected_count" ]; then
                    log_info "进入宽限期，等待最后一批处理完成（最多 ${GRACE_PERIOD}s）..."
                    grace_elapsed=0
                    while [ $grace_elapsed -lt $GRACE_PERIOD ]; do
                        current_count=$(get_db_count)
                        processed=$((current_count - before_count))

                        if [ "$current_count" -ge "$expected_count" ]; then
                            echo -ne "\r  宽限期进度: ${processed}/${array_length} 已处理 ✓          \n"
                            break
                        fi

                        # 显示宽限期进度
                        if [ "$current_count" -ne "$last_count" ]; then
                            echo -ne "\r  宽限期进度: ${processed}/${array_length} 已处理..."
                            last_count=$current_count
                        fi

                        sleep 1
                        grace_elapsed=$((grace_elapsed + 1))
                    done
                fi
            fi

            final_count=$(get_db_count)
            final_processed=$((final_count - before_count))
            
            if [ "$final_count" -ge "$expected_count" ]; then
                log_success "处理完成: $final_processed/$array_length"
                PASSED_TESTS=$((PASSED_TESTS + final_processed))
            else
                log_error "处理超时: 仅完成 $final_processed/$array_length（耗时 ${elapsed}s）"
                PASSED_TESTS=$((PASSED_TESTS + final_processed))
                FAILED_TESTS=$((FAILED_TESTS + array_length - final_processed))
            fi
            
            # ====== 阶段 3：统计分析结果 ======
            echo ""
            log_info "阶段 3/3：验证分析结果..."
            analysis_stats=$(docker exec browse-etl-postgres psql -U postgres -d behavior_analysis -tAc \
                "SELECT analysis_method, COUNT(*) FROM user_behaviors WHERE created_at > NOW() - INTERVAL '2 minutes' GROUP BY analysis_method ORDER BY analysis_method;" 2>/dev/null || echo "")
            
            if [ -n "$analysis_stats" ]; then
                echo "$analysis_stats" | while IFS='|' read -r method count; do
                    echo "  → $method: $count 条"
                done
            fi
            
            # 记录到报告
            {
                echo "✅ $test_name - 批量测试"
                echo "   发送成功: $send_success/$array_length"
                echo "   处理成功: $final_processed/$array_length"
                echo "   处理器模式: $PROCESSOR_MODE"
                echo ""
            } >> "$REPORT_FILE"
            
        else
            # 单个 JSON 对象：直接发送
            log_info "单个事件对象"
            
            # 统计总事件数
            TOTAL_EVENTS=$((TOTAL_EVENTS + 1))
            
            # 记录测试前的记录数
            before_count=$(get_db_count)
            
            # 发送事件
            echo -n "  → 发送事件..."
            send_result=$(send_event "$test_file")
            
            if [[ "$send_result" == "success" ]]; then
                echo -e " ${GREEN}✓${NC}"
                
                # 等待处理
                echo -n "  → 等待处理 (最多 ${WAIT_TIMEOUT}s)..."
                elapsed=0
                while [ $elapsed -lt $WAIT_TIMEOUT ]; do
                    current_count=$(get_db_count)
                    if [ "$current_count" -gt "$before_count" ]; then
                        echo -e " ${GREEN}✓${NC}"
                        
                        # 获取结果详情
                        record_info=$(get_latest_record)
                        IFS='|' read -r behavior_type analysis_method description <<< "$record_info"
                        
                        echo "  → 行为类型: ${behavior_type}"
                        echo "  → 分析方法: ${analysis_method}"
                        echo "  → 描述摘要: ${description:0:50}..."
                        
                        log_success "测试通过"
                        PASSED_TESTS=$((PASSED_TESTS + 1))
                        
                        # 记录到文件
                        {
                            echo "✅ $test_name"
                            echo "   行为类型: $behavior_type"
                            echo "   分析方法: $analysis_method"
                            echo "   描述: $description"
                            echo "   处理器模式: $PROCESSOR_MODE"
                            echo ""
                        } >> "$REPORT_FILE"
                        break
                    fi
                    sleep 1
                    elapsed=$((elapsed + 1))
                done
                
                if [ $elapsed -ge $WAIT_TIMEOUT ]; then
                    echo -e " ${RED}✗${NC}"
                    log_error "超时：未在规定时间内处理完成"
                    FAILED_TESTS=$((FAILED_TESTS + 1))
                    
                    {
                        echo "❌ $test_name"
                        echo "   错误: 处理超时"
                        echo ""
                    } >> "$REPORT_FILE"
                fi
            else
                echo -e " ${RED}✗${NC}"
                log_error "发送失败: $send_result"
                FAILED_TESTS=$((FAILED_TESTS + 1))
                
                {
                    echo "❌ $test_name"
                    echo "   错误: $send_result"
                    echo ""
                } >> "$REPORT_FILE"
            fi
        fi
        
        echo ""
    done
    
    # 生成测试总结
    END_TIME=$(date +%s)
    DURATION=$((END_TIME - START_TIME))
    final_db_count=$(get_db_count)
    new_records=$((final_db_count - initial_db_count))
    
    log_section "📊 测试总结"
    echo "测试文件:   $TOTAL_TESTS 个"
    echo "总事件数:   $TOTAL_EVENTS 个"
    echo -e "成功处理:   ${GREEN}$PASSED_TESTS${NC} 个"
    echo -e "处理失败:   ${RED}$FAILED_TESTS${NC} 个"
    if [ $TOTAL_EVENTS -gt 0 ]; then
        echo "成功率:     $(awk "BEGIN {printf \"%.1f%%\", ($PASSED_TESTS/$TOTAL_EVENTS)*100}")"
    fi
    echo ""
    echo "处理器模式: $PROCESSOR_MODE"
    echo "数据库记录: $initial_db_count → $final_db_count (+$new_records)"
    echo "总耗时:     ${DURATION}s"
    if [ $PASSED_TESTS -gt 0 ]; then
        echo "平均速度:   $(awk "BEGIN {printf \"%.2f\", $PASSED_TESTS/$DURATION}") events/s"
    fi
    echo ""
    echo "详细报告:   $REPORT_FILE"
    echo "=================================================="
    
    # 追加总结到报告文件
    {
        echo "================================================================================"
        echo "测试总结"
        echo "================================================================================"
        echo "结束时间: $(date)"
        echo "测试文件: $TOTAL_TESTS 个"
        echo "总事件数: $TOTAL_EVENTS 个"
        echo "成功处理: $PASSED_TESTS 个"
        echo "处理失败: $FAILED_TESTS 个"
        if [ $TOTAL_EVENTS -gt 0 ]; then
            echo "成功率: $(awk "BEGIN {printf \"%.1f%%\", ($PASSED_TESTS/$TOTAL_EVENTS)*100}")"
        fi
        echo "处理器模式: $PROCESSOR_MODE"
        echo "总耗时: ${DURATION}s"
        if [ $PASSED_TESTS -gt 0 ]; then
            echo "平均速度: $(awk "BEGIN {printf \"%.2f\", $PASSED_TESTS/$DURATION}") events/s"
        fi
        echo "数据库记录: $initial_db_count → $final_db_count (+$new_records)"
    } >> "$REPORT_FILE"
    
    # 查看详细统计
    log_section "📈 分析方法统计"
    docker exec browse-etl-postgres psql -U postgres -d behavior_analysis -c \
        "SELECT 
            analysis_method, 
            COUNT(*) as count,
            ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER(), 1) as percentage
         FROM user_behaviors 
         GROUP BY analysis_method 
         ORDER BY count DESC;" 2>/dev/null || log_warning "无法查询统计信息"
    
    # 返回退出码
    if [ $FAILED_TESTS -eq 0 ]; then
        log_success "所有测试通过！🎉"
        exit 0
    else
        log_error "有 $FAILED_TESTS 个测试失败"
        exit 1
    fi
}

# 执行主流程
main

